#include "VLCPlayer.h"

#include <SDL.h>
#include <SDL_mutex.h>

#include <vlc/vlc.h>

#include <main/Globals.h>
#include <main/MainConstants.h>

#include <utils/Error.h>

#define VIDEOWIDTH WINDOW_WIDTH
#define VIDEOHEIGHT WINDOW_HEIGHT

struct context {
    SDL_Texture *texture;
    SDL_mutex *mutex;
    int n;
};

static void *lock(void *data, void **p_pixels) {
    struct context *c = (context *)data;
    int pitch;
    SDL_LockMutex(c->mutex);
    SDL_LockTexture(c->texture, NULL, p_pixels, &pitch);
    return NULL; 
}

static void unlock(void *data, void *id, void *const *p_pixels) {
    struct context *c = (context *)data;
    SDL_UnlockTexture(c->texture);
    SDL_UnlockMutex(c->mutex);
}

static void display(void *data, void *id) {
    struct context *c = (context *)data;
	SDL_RenderCopy(Globals::gRenderer, c->texture, NULL, NULL);
    SDL_RenderPresent(Globals::gRenderer);
}

static void vlcEventCallback(const libvlc_event_t*, void* thisPtr) {
	VLCPlayer* vplayer = (VLCPlayer*)thisPtr;
	vplayer->isVideoStopped = true;
}

VLCPlayer::VLCPlayer(const std::string& file) : pauseState(false), file(file), isVideoStopped(false) {
	
}

VLCPlayer::~VLCPlayer() {}

void VLCPlayer::play() {
    context context;
    context.texture = SDL_CreateTexture(
            Globals::gRenderer,
            SDL_PIXELFORMAT_BGR565, SDL_TEXTUREACCESS_STREAMING,
            VIDEOWIDTH, VIDEOHEIGHT);
    if (!context.texture) {
        printError("Couldn't create texture");
    }

    context.mutex = SDL_CreateMutex();

    // Init library
	const char* arg1 = "--no-video-title-show";
	const char* filePtr = file.c_str();
	const char* args[3];
	args[1] = filePtr;
	args[2] = arg1;

    libvlc_instance_t* libvlc = libvlc_new(3, args);
    if(NULL == libvlc) {
        printError("LibVLC initialization failure.");
    }
	
	libvlc_media_t* m = libvlc_media_new_path(libvlc, filePtr);
    libvlc_media_player_t* mp = libvlc_media_player_new_from_media(m);
    libvlc_media_release(m);

	libvlc_event_manager_t* eventManager = libvlc_media_player_event_manager(mp);
	libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, &vlcEventCallback, this); 

    libvlc_video_set_callbacks(mp, lock, unlock, display, &context);
	libvlc_video_set_format(mp, "RV16", VIDEOWIDTH, VIDEOHEIGHT, VIDEOWIDTH*2);
    libvlc_media_player_play(mp);

    // SDL loop
	SDL_Event event;
    while(!isVideoStopped) {
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                exit(0);
                break;
            } else if (event.type == SDL_KEYDOWN) {      
                isVideoStopped = true;
                break;
            }
        }

        if(!pauseState) { 
			context.n++; 
		}

        SDL_Delay(1000/10);
    }

    // Stop stream and clean up libVLC.
    libvlc_media_player_stop(mp);
    libvlc_media_player_release(mp);
    libvlc_release(libvlc);

    // Close window and clean up libSDL.
    SDL_DestroyMutex(context.mutex);
}